package semaphore;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 信号量 vs 线程队列对比示例
 * 展示两种方式在处理并发任务时的不同行为
 */
public class SemaphoreVsQueueComparison {
    
    private static final int MAX_CONCURRENT = 3; // 最大并发数
    private static final int TOTAL_TASKS = 10;   // 总任务数
    
    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== 信号量 vs 线程队列对比 ===\n");
        
        // 1. 使用信号量的方式
        System.out.println("1. 使用信号量方式:");
        testWithSemaphore();
        
        Thread.sleep(2000);
        System.out.println("\n" + "=".repeat(50) + "\n");
        
        // 2. 使用线程池队列的方式
        System.out.println("2. 使用线程池队列方式:");
        testWithThreadPool();
        
        Thread.sleep(2000);
        System.out.println("\n" + "=".repeat(50) + "\n");
        
        // 3. 使用阻塞队列的方式
        System.out.println("3. 使用阻塞队列方式:");
        testWithBlockingQueue();
    }
    
    /**
     * 使用信号量的方式
     * 特点：多余的线程会被阻塞等待，直到有许可可用
     */
    private static void testWithSemaphore() throws InterruptedException {
        Semaphore semaphore = new Semaphore(MAX_CONCURRENT);
        AtomicInteger taskCounter = new AtomicInteger(0);
        
        System.out.println("创建 " + TOTAL_TASKS + " 个任务，信号量许可数: " + MAX_CONCURRENT);
        System.out.println("特点：超出许可数的线程会阻塞等待\n");
        
        // 创建所有任务线程
        Thread[] threads = new Thread[TOTAL_TASKS];
        for (int i = 0; i < TOTAL_TASKS; i++) {
            final int taskId = i + 1;
            threads[i] = new Thread(() -> {
                try {
                    System.out.println("任务-" + taskId + " 请求执行...");
                    
                    // 获取许可（可能阻塞）
                    semaphore.acquire();
                    
                    System.out.println("✅ 任务-" + taskId + " 开始执行 (当前并发: " + 
                                     (MAX_CONCURRENT - semaphore.availablePermits()) + ")");
                    
                    // 模拟任务执行
                    Thread.sleep(2000);
                    
                    System.out.println("✅ 任务-" + taskId + " 执行完成");
                    taskCounter.incrementAndGet();
                    
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.out.println("❌ 任务-" + taskId + " 被中断");
                } finally {
                    semaphore.release();
                }
            });
        }
        
        // 启动所有线程
        for (Thread thread : threads) {
            thread.start();
        }
        
        // 等待所有线程完成
        for (Thread thread : threads) {
            thread.join();
        }
        
        System.out.println("信号量方式完成，总共执行任务: " + taskCounter.get());
    }
    
    /**
     * 使用线程池队列的方式
     * 特点：任务会被放入队列等待执行，不会失败
     */
    private static void testWithThreadPool() throws InterruptedException {
        // 创建固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(MAX_CONCURRENT);
        AtomicInteger taskCounter = new AtomicInteger(0);
        
        System.out.println("创建 " + TOTAL_TASKS + " 个任务，线程池大小: " + MAX_CONCURRENT);
        System.out.println("特点：任务会排队等待，保证所有任务都会执行\n");
        
        // 提交所有任务
        for (int i = 1; i <= TOTAL_TASKS; i++) {
            final int taskId = i;
            executor.submit(() -> {
                try {
                    System.out.println("✅ 任务-" + taskId + " 开始执行");
                    
                    // 模拟任务执行
                    Thread.sleep(2000);
                    
                    System.out.println("✅ 任务-" + taskId + " 执行完成");
                    taskCounter.incrementAndGet();
                    
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.out.println("❌ 任务-" + taskId + " 被中断");
                }
            });
            System.out.println("任务-" + taskId + " 已提交到队列");
        }
        
        // 关闭线程池并等待完成
        executor.shutdown();
        executor.awaitTermination(30, TimeUnit.SECONDS);
        
        System.out.println("线程池方式完成，总共执行任务: " + taskCounter.get());
    }
    
    /**
     * 使用阻塞队列的方式
     * 特点：生产者-消费者模式，可以控制队列大小
     */
    private static void testWithBlockingQueue() throws InterruptedException {
        BlockingQueue<Integer> taskQueue = new LinkedBlockingQueue<>(5); // 队列容量为5
        AtomicInteger taskCounter = new AtomicInteger(0);
        
        System.out.println("创建 " + TOTAL_TASKS + " 个任务，队列容量: 5，工作线程: " + MAX_CONCURRENT);
        System.out.println("特点：队列满时生产者阻塞，队列空时消费者阻塞\n");
        
        // 创建消费者线程（工作线程）
        Thread[] workers = new Thread[MAX_CONCURRENT];
        for (int i = 0; i < MAX_CONCURRENT; i++) {
            final int workerId = i + 1;
            workers[i] = new Thread(() -> {
                try {
                    while (!Thread.currentThread().isInterrupted()) {
                        Integer taskId = taskQueue.take(); // 阻塞获取任务
                        if (taskId == -1) break; // 结束标志
                        
                        System.out.println("✅ 工作线程-" + workerId + " 执行任务-" + taskId);
                        
                        // 模拟任务执行
                        Thread.sleep(2000);
                        
                        System.out.println("✅ 工作线程-" + workerId + " 完成任务-" + taskId);
                        taskCounter.incrementAndGet();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
            workers[i].start();
        }
        
        // 生产者：添加任务到队列
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= TOTAL_TASKS; i++) {
                    System.out.println("生产者添加任务-" + i + " 到队列...");
                    taskQueue.put(i); // 阻塞添加
                    System.out.println("任务-" + i + " 已添加到队列 (队列大小: " + taskQueue.size() + ")");
                }
                
                // 发送结束信号
                for (int i = 0; i < MAX_CONCURRENT; i++) {
                    taskQueue.put(-1);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        producer.start();
        producer.join();
        
        // 等待所有工作线程完成
        for (Thread worker : workers) {
            worker.join();
        }
        
        System.out.println("阻塞队列方式完成，总共执行任务: " + taskCounter.get());
    }
}
